package edu.cmu.cs.stage3.alice.authoringtool.editors.variablegroupeditor;

import edu.cmu.cs.stage3.alice.authoringtool.AuthoringTool;
import edu.cmu.cs.stage3.alice.authoringtool.AuthoringToolResources;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.ElementReferenceTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.dialog.NewVariableContentPane;
import edu.cmu.cs.stage3.alice.authoringtool.event.AuthoringToolStateChangedEvent;
import edu.cmu.cs.stage3.resourceBundle.I18n;

/**
 * @author Jason Pratt
 */
public class VariableGroupEditor extends javax.swing.JPanel implements edu.cmu.cs.stage3.alice.core.event.ObjectArrayPropertyListener, java.awt.dnd.DropTargetListener {

 protected edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty variables;
 protected javax.swing.JButton newVariableButton = new javax.swing.JButton(I18n.getString("newGlobalVariable"));
 protected NewVariableContentPane newVariableDialog;
 protected AuthoringTool authoringTool;

 protected int lineLocation = -1;
 protected int variablePosition = 0;

 public VariableGroupEditor () {
  guiInit();
  }

 private void guiInit () {
  setLayout( new java.awt.GridBagLayout() );
  setBackground( java.awt.Color.white );
  newVariableButton.setBackground( new java.awt.Color( 240, 240, 255 ) );
  newVariableButton.setMargin( new java.awt.Insets( 2, 4, 2, 4 ) );
  newVariableButton.addActionListener(
    new java.awt.event.ActionListener() {
     public void actionPerformed( java.awt.event.ActionEvent ev) {
      if (authoringTool != null) {
       edu.cmu.cs.stage3.alice.core.Variable variable = authoringTool.showNewVariableDialog( "create new variable", variables.getOwner());
       if (variable != null) {
        authoringTool.getUndoRedoStack().startCompound();
        try {
         variables.getOwner().addChild( variable );
         variables.add( variable );
        } finally {
         authoringTool.getUndoRedoStack().stopCompound();
         }
        }
       }
      }
     } // new java.awt.event.ActionListener()
  );
  addContainerListener( edu.cmu.cs.stage3.alice.authoringtool.util.GUIElementContainerListener.getStaticListener() );
  setDropTarget( new java.awt.dnd.DropTarget( this, this ) );
  newVariableButton.setToolTipText( "<html><font face=arial size=-1>Open New Variable Dialog.<p><p>Variables allow you to store information.<p>You may choose among several types<p>of information (like Numbers, Booleans, and Objects).</font></html>" );

  refreshGUI();
  } // private void guiInit ()

 public javax.swing.JComponent getJComponent () {
  return this;
  }

 public void setVariableObjectArrayProperty (edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty variables) {
  if (this.variables != null) {
   this.variables.removeObjectArrayPropertyListener( this );
   }

  this.variables = variables;

  if (this.variables != null) {
   this.variables.addObjectArrayPropertyListener( this );
   }
  refreshGUI();
  }

 public void setAuthoringTool (AuthoringTool authoringTool) {
  this.authoringTool = authoringTool;
  }

 public javax.swing.JButton getNewVariableButton () {
  return newVariableButton;
  }

 public void refreshGUI () {
  this.removeAll();
  if (variables != null) {
   int count = 0;
   for (int i=0; i<variables.size(); i++) {
    if (variables.get( i ) instanceof edu.cmu.cs.stage3.alice.core.Variable) {
     final edu.cmu.cs.stage3.alice.core.Variable variable = (edu.cmu.cs.stage3.alice.core.Variable)variables.get( i );
     edu.cmu.cs.stage3.alice.authoringtool.util.PopupItemFactory factory = new edu.cmu.cs.stage3.alice.authoringtool.util.SetPropertyImmediatelyFactory( variable.value );
     javax.swing.JComponent gui = edu.cmu.cs.stage3.alice.authoringtool.util.GUIFactory.getVariableGUI( variable, true, factory );
     if (gui != null) {
      this.add( gui, new java.awt.GridBagConstraints( 0, count++, 1, 1, 1.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 2, 2, 2, 2 ), 0, 0 ) );
     } else {
      AuthoringTool.getInstance().showErrorDialog( "Unable to create gui for variable: " + variable, null );
      }
     }
    } // for (int i=0; i<variables.size(); i++)

   this.add( newVariableButton, new java.awt.GridBagConstraints( 0, count++, 1, 1, 1.0, 0.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 8, 2, 8, 2 ), 0, 0 ) );
   newVariableButton.setDropTarget( new java.awt.dnd.DropTarget( newVariableButton, this ) );
   java.awt.Component glue = javax.swing.Box.createGlue();
   this.add( glue, new java.awt.GridBagConstraints( 0, count++, 1, 1, 1.0, 1.0, java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 2, 2, 2, 2 ), 0, 0 ) );
   glue.setDropTarget( new java.awt.dnd.DropTarget( glue, this ) );
   }
  revalidate();
  repaint();
  }

 // line drawing
 //Rem @Override
 public void paintComponent (java.awt.Graphics g) {
  super.paintComponent( g );
  if (lineLocation > -1) {
   java.awt.Rectangle bounds = getBounds();
   g.setColor( java.awt.Color.black );
   g.fillRect( 0, lineLocation, bounds.width, 2 );
   }
  }


 ///////////////////////////////////////////////
 // DropTargetListener interface
 ///////////////////////////////////////////////

 protected void calculateLineLocation (int mouseY) {
  int numSpots = variables.size() + 1;
  int[] spots = new int[numSpots];
  spots[0] = 0;
  for (int i=1; i<numSpots; i++) {
   java.awt.Component c = getComponent( i - 1 );
   spots[i] = c.getBounds().y + c.getBounds().height + 1; // assumes gridBagConstraints insets.bottom == 2
  }

  int closestSpot = -1;
  int minDist = Integer.MAX_VALUE;
  for (int i=0; i<numSpots; i++) {
   int d = Math.abs( mouseY - spots[i] );
   if (d < minDist) {
    minDist = d;
    closestSpot = i;
    }
   }

  variablePosition = closestSpot;
  lineLocation = spots[closestSpot];
  }

 public void dragEnter (java.awt.dnd.DropTargetDragEvent dtde) {
  // System.out.println("\n\nVariableGroupEditor.java: dragEnter(java.awt.dnd.DropTargetDropEvent)");
  if (AuthoringToolResources.safeIsDataFlavorSupported(dtde, ElementReferenceTransferable.variableReferenceFlavor )) {
   dtde.acceptDrag( java.awt.dnd.DnDConstants.ACTION_MOVE );
   int mouseY = javax.swing.SwingUtilities.convertPoint( dtde.getDropTargetContext().getComponent(), dtde.getLocation(), this ).y;
   calculateLineLocation( mouseY );
  } else {
   lineLocation = -1;
   dtde.rejectDrag();
  }
  repaint();
 }

 public void dragOver (java.awt.dnd.DropTargetDragEvent dtde) {
  if (AuthoringToolResources.safeIsDataFlavorSupported(dtde, ElementReferenceTransferable.variableReferenceFlavor )) {
   dtde.acceptDrag( java.awt.dnd.DnDConstants.ACTION_MOVE );
   int mouseY = javax.swing.SwingUtilities.convertPoint( dtde.getDropTargetContext().getComponent(), dtde.getLocation(), this ).y;
   calculateLineLocation( mouseY );
  } else {
   lineLocation = -1;
   dtde.rejectDrag();
  }
  repaint();
 }

 public void drop (java.awt.dnd.DropTargetDropEvent dtde) {
  java.awt.datatransfer.Transferable transferable = dtde.getTransferable();
  // System.out.println("\n\nVariableGroupEditor.java: drop(java.awt.dnd.DropTargetDropEvent)");
  if (AuthoringToolResources.safeIsDataFlavorSupported(transferable, ElementReferenceTransferable.variableReferenceFlavor )) {
   dtde.acceptDrop( java.awt.dnd.DnDConstants.ACTION_MOVE );
   try {
    edu.cmu.cs.stage3.alice.core.Variable variable = (edu.cmu.cs.stage3.alice.core.Variable)transferable.getTransferData( ElementReferenceTransferable.variableReferenceFlavor );
    if (variables.contains( variable )) {
     if (variablePosition > variables.indexOf( variable )) {
      variablePosition--;
     }
     variables.remove( variable );
    }
    variables.add( variablePosition, variable );
    dtde.dropComplete( true );
   } catch( java.awt.datatransfer.UnsupportedFlavorException e) {
    System.err.println("Error: VariableGroupEditor.java: drop(java.awt.dnd.DropTargetDropEvent): "+e.toString());
    AuthoringTool.getInstance().showErrorDialog( "Drop didn't work: bad flavor", e );
    dtde.dropComplete( false );
   } catch( java.io.IOException e) {
    System.err.println("Error: VariableGroupEditor.java: drop(java.awt.dnd.DropTargetDropEvent): "+e.toString());
    AuthoringTool.getInstance().showErrorDialog( "Drop didn't work: IOException", e );
    dtde.dropComplete( false );
   } catch( Throwable t) {
    System.err.println("Error: VariableGroupEditor.java: drop(java.awt.dnd.DropTargetDropEvent): "+t.toString());
    AuthoringTool.getInstance().showErrorDialog( "Drop didn't work.", t );
    dtde.dropComplete( false );
    }
  } else {
   System.err.println("Error: VariableGroupEditor.java: drop(java.awt.dnd.DropTargetDropEvent): rejected drop");
   dtde.rejectDrop();
   dtde.dropComplete( false );
   }
  lineLocation = -1;
  repaint();
  }

 public void dropActionChanged (java.awt.dnd.DropTargetDragEvent dtde) {
  if (AuthoringToolResources.safeIsDataFlavorSupported(dtde, ElementReferenceTransferable.variableReferenceFlavor )) {
   dtde.acceptDrag( java.awt.dnd.DnDConstants.ACTION_MOVE );
  } else {
   dtde.rejectDrag();
   }
  }

 public void dragExit (java.awt.dnd.DropTargetEvent dte) {
  lineLocation = -1;
  repaint();
  }


 ///////////////////////////////////////////////
 // ChildrenListener interface
 ///////////////////////////////////////////////

 public void objectArrayPropertyChanging (edu.cmu.cs.stage3.alice.core.event.ObjectArrayPropertyEvent ev) { }

 public void objectArrayPropertyChanged (edu.cmu.cs.stage3.alice.core.event.ObjectArrayPropertyEvent ev) {
  refreshGUI();
  }


 ///////////////////////////////////////////////
 // AuthoringToolStateListener interface
 ///////////////////////////////////////////////

 public void stateChanging( AuthoringToolStateChangedEvent ev) { }
 public void worldLoading( AuthoringToolStateChangedEvent ev) { }
 public void worldUnLoading( AuthoringToolStateChangedEvent ev) { }
 public void worldStarting( AuthoringToolStateChangedEvent ev) { }
 public void worldStopping( AuthoringToolStateChangedEvent ev) { }
 public void worldPausing( AuthoringToolStateChangedEvent ev) { }
 public void worldSaving( AuthoringToolStateChangedEvent ev) { }
 public void stateChanged( AuthoringToolStateChangedEvent ev) { }

 public void worldLoaded( AuthoringToolStateChangedEvent ev) { }
 public void worldUnLoaded( AuthoringToolStateChangedEvent ev) { }
 public void worldStarted( AuthoringToolStateChangedEvent ev) { }
 public void worldStopped( AuthoringToolStateChangedEvent ev) { }
 public void worldPaused( AuthoringToolStateChangedEvent ev) { }
 public void worldSaved( AuthoringToolStateChangedEvent ev) { }

 }
